package com.nx.vip.factory;

import com.google.auto.service.AutoService;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 注解解析器
 */
@AutoService(Processor.class)
@SupportedAnnotationTypes("com.nx.vip.factory.Factory") //解析哪个注解
@SupportedSourceVersion(SourceVersion.RELEASE_8)        //哪个版本
public class FactoryProcessor extends AbstractProcessor {

    private Types typeUtils;    //工具，一个用来处理TypeMirror的工具类
    private Elements elementUtils;//所有的元素，处理元素，代表源代码的一些东西，如注解，包,一个用来处理Element的工具类
    private Filer filer;        //使用Filer你可以创建文件
    private Messager messager;  //需要用到的Messager,警告，错误，异常提示，使用这个

    private Map<String,FactoryGroupedClasses> factoryGroupedClassesMap = new HashMap<>();//所有加了注解的

    /**
     * 初始化，有哪些个文件，以及文件中的类型是的什么，以及文件中的元素是什么
     * 还有出现问题的时候，使用注解解析器，进行打印操作
     * @param processingEnv
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        typeUtils = processingEnv.getTypeUtils();
        elementUtils = processingEnv.getElementUtils();
        filer = processingEnv.getFiler();
        messager = processingEnv.getMessager();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        try {
            //遍历所有被注解了@Factory的元素
            for(Element annotatedElement : roundEnv.getElementsAnnotatedWith(Factory.class)){
                if (annotatedElement.getKind()!= ElementKind.CLASS){//检查元素是不是加在Class上，因为Element可以是类、方法、变量等
                    throw new ProcessingException(annotatedElement,"Only class can be annotated with @%s",Factory.class.getSimpleName());
                }
                //类类型的注解
                TypeElement typeElement = (TypeElement) annotatedElement;
                //封装注解为注解类，为了以后让它生成一个class文件，可以获取全类名，类名
                FactoryAnnotatedClass annotatedClass = new FactoryAnnotatedClass(typeElement);
                //下面这一块的代码含义：把所有加了@Factory的类进行一个包装，包装成一个group
                //factoryGroupedClassesMap<@Factory,Map<"Mile",FactoryAnnotatedClass>>
                FactoryGroupedClasses factoryGroupedClasses  = factoryGroupedClassesMap.get(annotatedClass.getQualifiedSuperClassName());
                //如果没有的话，组成双层map
                if (factoryGroupedClasses ==null){
                    String qualifiedFactoryGroupName = annotatedClass.getQualifiedSuperClassName();//获取到全组名
                    factoryGroupedClasses = new FactoryGroupedClasses(qualifiedFactoryGroupName);
                    factoryGroupedClassesMap.put(qualifiedFactoryGroupName,factoryGroupedClasses);
                }
                //把所有加了@Factory 封装成 factoryGroupedClassesMap<@Factory,Map<"Mile",FactoryAnnotatedClass>>
                factoryGroupedClasses.add(annotatedClass);
                //类中生成代码
                factoryGroupedClasses.generateCode(elementUtils,filer);
                factoryGroupedClassesMap.clear();


            }

        }catch (ProcessingException e){
            error(e.getElement(),e.getMessage());
        } catch (IOException e) {
           error(null,e.getMessage());//不是元素导致的异常
        }catch (IllegalArgumentException e) {
            // @Factory.id()为空
            error(null, e.getMessage());
        }


        return false;
    }

    public void error(Element e,String msg){
        messager.printMessage(Diagnostic.Kind.ERROR,msg,e);
    }
}
